#pragma once

#include "BehavioralFeature.h"

#include "Behavior.h"
#include "NamedElement.h"
#include "Namespace.h"
#include "Parameter.h"
#include "ParameterSet.h"
#include "Type.h"

namespace uml {

const bool BehavioralFeature::isAbstract_default_ = false;
BehavioralFeature::BehavioralFeature(const QString& umlType)
    : Feature(umlType) {}

void BehavioralFeature::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    Feature::fromJson(json, errorList);
    Namespace::fromJson(json, errorList);
    concurrency_ = (CallConcurrencyKind)json.value("concurrency").toInt((int)concurrency_);
    isAbstract_ = json.value("isAbstract").toBool(isAbstract_default_);
    JsonSerializable::fromJsonArray(methods_, "methods", json, errorList);
    JsonSerializable::fromJsonArray(ownedParameters_, "ownedParameters", json, errorList);
    JsonSerializable::fromJsonArray(ownedParameterSets_, "ownedParameterSets", json, errorList);
    JsonSerializable::fromJsonArray(raisedExceptions_, "raisedExceptions", json, errorList);
}

void BehavioralFeature::toJson(QJsonObject& json) {
    Feature::toJson(json);
    Namespace::toJson(json);
    json.insert("concurrency", (int)concurrency_);
    if (isAbstract_ != isAbstract_default_) {
        json.insert("isAbstract", isAbstract_);
    }
    JsonSerializable::toJsonArray(methods_, "methods", json);
    JsonSerializable::toJsonArray(ownedParameters_, "ownedParameters", json);
    JsonSerializable::toJsonArray(ownedParameterSets_, "ownedParameterSets", json);
    JsonSerializable::toJsonArray(raisedExceptions_, "raisedExceptions", json);
}

/// <summary>
/// isDistinguishableFrom
    /// The query isDistinguishableFrom() determines whether two BehavioralFeatures may
    /// coexist in the same Namespace. It specifies that they must have different
    /// signatures.
/// </summary>
    /// <code>
    /// result = ((n.oclIsKindOf(BehavioralFeature) and ns.getNamesOfMember(self)->intersection(ns.getNamesOfMember(n))->notEmpty()) implies
    ///   Set{self}->including(n.oclAsType(BehavioralFeature))->isUnique(ownedParameter->collect(p|
    ///   Tuple { name=p.name, type=p.type,effect=p.effect,direction=p.direction,isException=p.isException,
    ///               isStream=p.isStream,isOrdered=p.isOrdered,isUnique=p.isUnique,lower=p.lower, upper=p.upper }))
    ///   )
    /// </code>
bool BehavioralFeature::isDistinguishableFrom(shared_ptr<NamedElement> n, shared_ptr<Namespace> ns) const
{
    return false;
}

/// <summary>
/// inputParameters
    /// The ownedParameters with direction in and inout.
/// </summary>
    /// <code>
    /// result = (ownedParameter->select(direction=ParameterDirectionKind::_'in' or direction=ParameterDirectionKind::inout))
    /// </code>
shared_ptr<vector<Parameter>> BehavioralFeature::inputParameters() const
{
    return nullptr;
}

/// <summary>
/// outputParameters
    /// The ownedParameters with direction out, inout, or return.
/// </summary>
    /// <code>
    /// result = (ownedParameter->select(direction=ParameterDirectionKind::out or direction=ParameterDirectionKind::inout or direction=ParameterDirectionKind::return))
    /// </code>
shared_ptr<vector<Parameter>> BehavioralFeature::outputParameters() const
{
    return nullptr;
}

/// <summary>
/// concurrency getter
/// Specifies the semantics of concurrent calls to the same passive instance (i.e.,
/// an instance originating from a Class with isActive being false). Active
/// instances control access to their own BehavioralFeatures.
/// </summary>
CallConcurrencyKind BehavioralFeature::concurrency() const {
    return concurrency_;
}

/// <summary>
/// concurrency setter
/// Specifies the semantics of concurrent calls to the same passive instance (i.e.,
/// an instance originating from a Class with isActive being false). Active
/// instances control access to their own BehavioralFeatures.
/// </summary>
void BehavioralFeature::setConcurrency(CallConcurrencyKind value) {
    concurrency_ = value;
}

/// <summary>
/// isAbstract getter
/// If true, then the BehavioralFeature does not have an implementation, and one
/// must be supplied by a more specific Classifier. If false, the BehavioralFeature
/// must have an implementation in the Classifier or one must be inherited.
/// </summary>
bool BehavioralFeature::isAbstract() const {
    return isAbstract_;
}

/// <summary>
/// isAbstract setter
/// If true, then the BehavioralFeature does not have an implementation, and one
/// must be supplied by a more specific Classifier. If false, the BehavioralFeature
/// must have an implementation in the Classifier or one must be inherited.
/// </summary>
void BehavioralFeature::setIsAbstract(bool value) {
    isAbstract_ = value;
}

/// <summary>
/// methods getter
/// A Behavior that implements the BehavioralFeature. There may be at most one
/// Behavior for a particular pairing of a Classifier (as owner of the Behavior) and
/// a BehavioralFeature (as specification of the Behavior).
/// </summary>
vector<shared_ptr<Behavior>>& BehavioralFeature::methods() {
    return methods_;
}

/// <summary>
/// ownedParameters getter
/// The ordered set of formal Parameters of this BehavioralFeature.
/// </summary>
vector<shared_ptr<Parameter>>& BehavioralFeature::ownedParameters() {
    return ownedParameters_;
}

/// <summary>
/// ownedParameterSets getter
/// The ParameterSets owned by this BehavioralFeature.
/// </summary>
vector<shared_ptr<ParameterSet>>& BehavioralFeature::ownedParameterSets() {
    return ownedParameterSets_;
}

/// <summary>
/// raisedExceptions getter
/// The Types representing exceptions that may be raised during an invocation of
/// this BehavioralFeature.
/// </summary>
vector<shared_ptr<Type>>& BehavioralFeature::raisedExceptions() {
    return raisedExceptions_;
}

} // namespace uml
